package com.origin.oss.solution.ali;

import com.alibaba.fastjson2.JSON;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.*;
import com.origin.oss.enums.StorageType;
import com.origin.oss.manager.AliOssUploadManager;
import com.origin.oss.specification.domain.multipart.response.CompleteSliceUploadResp;
import com.origin.oss.specification.domain.multipart.SliceUploadInfo;
import com.origin.oss.solution.ali.config.AliOssConfig;
import com.origin.oss.specification.IOssClient;
import com.origin.oss.specification.domain.multipart.MultipartFileWrap;
import com.origin.oss.specification.domain.multipart.response.QuickUploadResp;
import com.origin.oss.specification.domain.multipart.request.SliceUploadReq;
import com.origin.oss.specification.domain.multipart.response.SliceUploadResp;
import com.origin.oss.specification.domain.object.UploadObjectDomain;
import com.origin.oss.util.FileStorageUtils;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Comparator;
import java.util.List;

/**
 * @author yezh
 * @date 2024/2/21 19:15
 * @see <a href="https://help.aliyun.com/product/31815.html">ali oss</a>
 */
@Data
@RequiredArgsConstructor
@Slf4j
public class AliOssClient implements IOssClient {

    private final OSS ossClient;
    private final AliOssConfig aliOssConfig;

    @Autowired
    private AliOssUploadManager aliOssUploadManager;

    @Override
    public StorageType getStorageType() {
        return StorageType.ALIYUN;
    }

    @Override
    public UploadObjectDomain uploadFile(String fileKey, InputStream is, boolean isOverride) {
        return null;
    }

    @Override
    public QuickUploadResp quickUpload(String identifier) {
        return null;
    }

    @Override
    public SliceUploadResp sliceUpload(SliceUploadReq sliceUploadReq) {
        String identifier = sliceUploadReq.getIdentifier();
        MultipartFileWrap qiwenFile = sliceUploadReq.getFile();

        SliceUploadInfo uploadFileInfo = aliOssUploadManager.getSliceUploadInfo(identifier);
        if (uploadFileInfo == null) {
            String fileUrl = qiwenFile.getFileUrl();
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(aliOssConfig.getBucketName(), fileUrl);
            InitiateMultipartUploadResult upResult = ossClient.initiateMultipartUpload(request);
            String uploadId = upResult.getUploadId();

            uploadFileInfo = new SliceUploadInfo();
            uploadFileInfo.setKey(fileUrl);
            uploadFileInfo.setUploadId(uploadId);
            uploadFileInfo.setBucketName(aliOssConfig.getBucketName());
            uploadFileInfo.setImage(qiwenFile.isImage());
            aliOssUploadManager.storeUploadPartRequest(uploadFileInfo, identifier);
        }

        boolean success = true;
        try (InputStream is = qiwenFile.getUploadInputStream()) {
            UploadPartRequest uploadPartRequest = new UploadPartRequest();
            uploadPartRequest.setBucketName(uploadFileInfo.getBucketName());
            uploadPartRequest.setKey(uploadFileInfo.getKey());
            uploadPartRequest.setUploadId(uploadFileInfo.getUploadId());
            uploadPartRequest.setInputStream(is);
            uploadPartRequest.setPartSize(qiwenFile.getSize());
            uploadPartRequest.setPartNumber(sliceUploadReq.getChunkNumber());
            log.debug(JSON.toJSONString(uploadPartRequest));

            UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
            log.debug("上传结果：{}", JSON.toJSONString(uploadPartResult));

            aliOssUploadManager.storePartETag(uploadPartResult.getPartETag(), identifier);
        } catch (IOException e) {
            log.error("分片上传失败 - identifier: {}, chunkNumber: {}", identifier, sliceUploadReq.getChunkNumber(), e);
            success = false;
        } finally {
            ossClient.shutdown();
        }
        return new SliceUploadResp()
                .setUploadId(uploadFileInfo.getUploadId())
                .setIdentifier(identifier)
                .setFileName(qiwenFile.getFileName())
                .setExtendName(qiwenFile.getExtendName())
                .setFileUrl(uploadFileInfo.getKey())
                .setFileSize(sliceUploadReq.getTotalSize())
                .setStorageType(getStorageType())
                .setSuccess(success);
    }

    @Override
    public boolean checkSliceUploadComplete(SliceUploadReq sliceUploadReq) {
        return aliOssUploadManager.countPartETag(sliceUploadReq.getIdentifier()) == sliceUploadReq.getTotalChunks();
    }

    @Override
    public CompleteSliceUploadResp completeSliceUpload(SliceUploadReq sliceUploadReq) {
        String identifier = sliceUploadReq.getIdentifier();

        SliceUploadInfo uploadFileInfo = aliOssUploadManager.getSliceUploadInfo(identifier);
        completeSliceUpload(identifier, uploadFileInfo);
        aliOssUploadManager.clearCache(identifier);

        CompleteSliceUploadResp fileUploadResult = new CompleteSliceUploadResp();
        if (uploadFileInfo.isImage()) {
            OSSObject ossObject = ossClient.getObject(aliOssConfig.getBucketName(),
                    FileStorageUtils.getAliyunObjectNameByFileUrl(uploadFileInfo.getKey()));
            BufferedImage srbufferedImage;
            try (InputStream is = ossObject.getObjectContent()) {
                srbufferedImage = ImageIO.read(is);
                fileUploadResult.setBufferedImage(srbufferedImage);
            } catch (IOException e) {
                // todo 异常处理
            }
        }
        return fileUploadResult;
    }

    @Override
    public void abortSliceUpload(SliceUploadReq sliceUploadReq) {

    }

    private void completeSliceUpload(String identifier, SliceUploadInfo uploadFileInfo) {
        List<PartETag> partETags = aliOssUploadManager.listPartETag(identifier);
        partETags.sort(Comparator.comparingInt(PartETag::getPartNumber));

        CompleteMultipartUploadRequest completeMultipartUploadRequest =
                new CompleteMultipartUploadRequest(aliOssConfig.getBucketName(),
                        uploadFileInfo.getKey(),
                        uploadFileInfo.getUploadId(),
                        partETags);
        // 完成上传
        ossClient.completeMultipartUpload(completeMultipartUploadRequest);
        ossClient.shutdown();
    }

}
